using Reversi;

//
// Modified: 2009/09/28, Jeremiah Blanchard (Full Sail)
namespace FullSailAFI.GamePlaying
{
    class MinimaxBehavior : Reversi.Behavior
    {
        //
        // The agent's knowledge is key to proper use of this behavior.
        //
        private Agent agent;

        //
        // Behavior constructor
        //
        public MinimaxBehavior(Agent _agent)
        {
            agent = _agent;
        }

        //
        // This function starts the look ahead process to find the best move
        // for the current player color.
        //
        public bool run()
        {
            // Kick off the look ahead.
            agent.move = GetBestMove(agent.board, agent.color, agent.lookAheadDepth);

            return (agent.move != null);
        }

        //
        // This function uses look ahead to evaluate all valid moves for a
        // given player color and returns the best move it can find. This
        // method will only be called if there is at least one valid move
        // for the player of the designated color.
        //
        public ComputerMove GetBestMove(Board board, int color, int depth)
        {
            ComputerMove bestMove = null;
            Board newBoard = new Board(board);
            int rank = 0;
            //
            // TODO: Perform minimax for each move to determine which is best.
            //

            // Take a look at all positions on the screen.
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)                
                {
                    newBoard.Copy(board);
                    //agent.move = new ComputerMove(row, col);
                    //
                    // If the move is valid:
                    //
                    //  - Apply the move to a copy of the board.
                    if (newBoard.IsValidMove(color, row, col))
                    {
                        newBoard.MakeMove(color, row, col);

                        //  - If the end of game or depth limit is reached, set the
                        //    rank of the current move based on the Board's
                        //    evaluation.
                        //
                        if (newBoard.IsTerminalState() || depth == 0)
                        {
                            rank = Evaluate(newBoard, color);
                            //rank += 1;
                        }
                        //  - Otherwise, determine the next game move using
                        //    recursion and set the rank of the current move to that
                        //    of the next move.
                        //
                        else
                        {
                            if (newBoard.HasAnyValidMove(-color))
                                rank = GetBestMove(newBoard, -color, depth - 1).rank;
                             else
                                 rank = GetBestMove(newBoard, color, depth - 1).rank;
                        }
                        //  - Keep track of the best move executed so far.
                        //
                        if (bestMove != null)
                        {
                            if (color == 1)
                            {
                                if (rank > bestMove.rank)
                                {
                                    bestMove.col = col;
                                    bestMove.row = row;
                                    bestMove.rank = rank;
                                    //bestMove = agent.move;
                                }
                            }
                            else
                            {
                                if (rank < bestMove.rank)
                                {
                                    bestMove.col = col;
                                    bestMove.row = row;
                                    bestMove.rank = rank;
                                    // bestMove = agent.move;
                                }
                            }

                        }
                        else
                        {
                            bestMove = new ComputerMove(row, col);
                            bestMove.rank = rank;
                        }
                        //
                        // NOTE: Don't forget - if there are no valid moves for the
                        //       next player, play is returned to the original
                        //       player (forfeit recognition.)
                        //
                        //       Remember - the rank is color neutral. A negative
                        //       number is good for black, and a positive number
                        //       is good for white.
                        //

                    }
                }

            // Return the best move found.

            return bestMove;
        }

        private int Evaluate(Board board, int color)
        {
            return board.Evaluate(agent.scoreWeight, agent.forfeitWeight, color);
        }
    }
}
